
#include <string.h>

#include "drv_usb_hw.h"
#include "cdc_acm_core.h"

#include "debug.h"
#include "utility.h"

#include "FreeRTOS.h"
#include "Task.h"
#include "Timers.h"
#include "Semphr.h"
#include "stream_buffer.h"
#include "simple_protocol.h"

usb_core_driver cdc_acm;

static StreamBufferHandle_t usbStreamBuffer;

int usb_cdc_init(void)
{
	usbStreamBuffer = xStreamBufferCreate(2048, 1);
	if(!usbStreamBuffer){
		LOG_E("no memory!");
		return -1;
	}
	
    usb_gpio_config();
    usb_rcu_config();
    usbd_init(&cdc_acm, &cdc_desc, &cdc_class);
    usb_intr_config();
	return 0;
}

static int usb_cdc_is_ready(void)
{
	return (USBD_CONFIGURED == cdc_acm.dev.cur_status);
}

void usb_cdc_data_send(const uint8_t *data, uint16_t len)
{
	if(!usb_cdc_is_ready()){
		return ;
	}
	
	uint32_t sent = 0;
	while(sent != len)
	{
		while(0U != cdc_acm_check_ready_send(&cdc_acm)){
			taskYIELD();
		}
		uint32_t length = UTIL_MIN(len - sent, 63);
		cdc_acm_data_send2(&cdc_acm, (uint8_t*)data + sent, length);
		sent += length;
	}
}

void usb_cdc_data_recv(uint8_t *data, uint8_t len)
{
	BaseType_t xHigherPriorityTaskWoken = pdFALSE;
	simpleProtocol_Notify(PROTOCOL_USB_BIT);
	int size = xStreamBufferSendFromISR(usbStreamBuffer, data, len, &xHigherPriorityTaskWoken);
	if(size != len){
		LOG_E("rx drop");
	}
	portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

int usb_cdc_get_byte(int wtime){
	uint8_t rx;
	if(!usb_cdc_is_ready()){
		return -2;
	}
	
	if(!cdc_acm_check_packet_receive(&cdc_acm)){
		cdc_acm_receive_init(&cdc_acm);
	}
	
	if(xStreamBufferReceive(usbStreamBuffer, &rx, sizeof(rx), wtime) > 0){
		return rx;
	}
	
	return -1;
}

int usb_cdc_check_rx(void){
	return pdFALSE == xStreamBufferIsEmpty(usbStreamBuffer);
}

void usb_cdc_clear_rx(void){
	xStreamBufferReset(usbStreamBuffer);
}


